#include "stdafx.h"
#include <boost/variant.hpp>

#if 0
namespace sgp{ namespace detail
{

	//! STCI header.
	class STCIHeader
	{
		// Inner class
	public:
		//! RGB structure.
		struct Rgb
		{
			unsigned int m_RedMask;
			unsigned int m_GreenMask;
			unsigned int m_BlueMask;
			unsigned int m_AlphaMask;
			unsigned short m_RedDepth;
			unsigned short m_GreenDepth;
			unsigned short m_BlueDepth;
			unsigned short m_AlphaDepth;

			// Construction
			Rgb()
				: m_RedMask(0), m_GreenMask(0), m_BlueMask(0)
			{
			}
		};

		struct Indexed
		{
			unsigned int m_NumberOfColors;
			unsigned short m_NumberOfSubImages;
			unsigned int m_RedDepth;
			unsigned int m_GreenDepth;
			unsigned int m_BlueDepth;
		};

		// Enums
	public:
		//! Image format type.
		enum FormatType
		{
			FT_RGB = 1,
			FT_INDEXED
		};

		// Attributes
	public:
		static unsigned short const HEADER_SIZE = 64;
		static unsigned short const ID_LEN = 4;
		static unsigned short const FLAG_INDEXED = 0x0008;
		static unsigned short const FLAG_RGB = 0x0004;
		static unsigned short const ETRLE_COMPRESSED = 0x0020;
		static char const ID_STIRNG[];
		//! Original size.
		size_t m_OriginalSize;
		//! Stored size.
		/*!
			Equal to m_OriginalSize if data umcompressed.
		*/
		size_t m_StoredSize;
		//! Transparent color value.
		boost::uint32_t m_TransparentColor;
		//! Image format type
		FormatType m_Type;
		//! Width of image.
		unsigned short m_Width;
		//! Height of image.
		unsigned short m_Height;
		//! BPP as stored in file.
		unsigned short m_BPP;
		//! ?AppDataSize?
		size_t m_AppDataSize;
		//! Union of RGB vs. Indexes
		boost::variant<Rgb, Indexed> m_Union;
		//! Image is compressed.
		bool m_ETRLECompressed;
		//! Zip compressed
		bool m_ZIPCompress;

		// Construction/Destruction
		STCIHeader()
			: m_ETRLECompressed(false), m_ZIPCompress(false)
		{
		}
	};


	//! Load the STCI file
	void load_stci(Ogre::DataStream &Stream)
	{
		boost::uint32_t uint32_holder;
		boost::uint16_t uint16_holder;
		boost::uint8_t uint8_holder;
		std::string string_holder;
		// Size of union buffer
		static const unsigned short UNION_SIZE = 20;
		char buffer[512];
		unsigned char union_buffer[UNION_SIZE];

		char *p_buffer_iterator = buffer;
		// Read head
		Stream.read(buffer, STCIHeader::HEADER_SIZE);
		// Parse header
		STCIHeader stci_header;
		string_holder.assign(p_buffer_iterator, STCIHeader::ID_LEN);
		p_buffer_iterator += STCIHeader::ID_LEN;
		// Is it STCI image
		if(string_holder != STCIHeader::ID_STIRNG)
			OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "This is not a STCI file!", "load_stci");
		// Fill original size
		memcpy(&uint32_holder, p_buffer_iterator, sizeof(uint32_holder));
		p_buffer_iterator += sizeof(uint32_holder);
		stci_header.m_OriginalSize = uint32_holder;
		// Fill stored size
		memcpy(&uint32_holder, p_buffer_iterator, sizeof(uint32_holder));
		p_buffer_iterator += sizeof(uint32_holder);
		stci_header.m_StoredSize = uint32_holder;
		// Fill transparent color value
		memcpy(&uint32_holder, p_buffer_iterator, sizeof(uint32_holder));
		p_buffer_iterator += sizeof(uint32_holder);
		stci_header.m_TransparentColor = uint32_holder;
		// Set flags
		memcpy(&uint32_holder, p_buffer_iterator, sizeof(uint32_holder));
		p_buffer_iterator += sizeof(uint32_holder);
		stci_header.m_Type = (uint32_holder & STCIHeader::FLAG_RGB) ? STCIHeader::FT_RGB : STCIHeader::FT_INDEXED;
		stci_header.m_ETRLECompressed = (uint32_holder & STCIHeader::ETRLE_COMPRESSED) ? true : false;
		// Fill width and height
		memcpy(&uint16_holder, p_buffer_iterator, sizeof(uint16_holder));
		p_buffer_iterator += sizeof(uint16_holder);
		stci_header.m_Height = uint16_holder;
		memcpy(&uint16_holder, p_buffer_iterator, sizeof(uint16_holder));
		p_buffer_iterator += sizeof(uint16_holder);
		stci_header.m_Width = uint16_holder;
		// Read data for union (variant)
		memcpy(union_buffer, p_buffer_iterator, UNION_SIZE);
		p_buffer_iterator += UNION_SIZE;
		// Read bpp
		memcpy(&uint8_holder, p_buffer_iterator, sizeof(uint8_holder));
		stci_header.m_BPP = uint8_holder;
		p_buffer_iterator += sizeof(uint8_holder);
		// Read AppDataSize?
		memcpy(&uint32_holder, p_buffer_iterator, sizeof(uint32_holder));
		stci_header.m_AppDataSize = uint32_holder;
		// Dtermine the data type stored in file
		switch(stci_header.m_Type)
		{
		case STCIHeader::FT_RGB:
			{
				// Allocate memory for data
				unsigned char *p_image_data = new unsigned char[stci_header.m_StoredSize];
				// Read data
				rFile.read(p_image_data, stci_header.m_StoredSize);
				CL_PixelBuffer px_buffer(stci_header.m_Width, stci_header.m_Height, 
					(stci_header.m_BPP / 8) * stci_header.m_Width, CL_PixelFormat::rgb565, 
					p_image_data, &detail::pixel_deleter);
				// Create sprite
				sprite_desc.add_frame(px_buffer);
				//					p_pixel_array->push_back(PixelData_t(p_image_data));
			}
			break;
		case STCIHeader::FT_INDEXED:
			{
				static const unsigned short PALETTE_ELEMENT_SIZE = 3;
				STCIHeader::Indexed indexed;
				// Fill indexed variant
				p_buffer_iterator = reinterpret_cast<char*>(union_buffer);
				// Get number of colors
				memcpy(&uint32_holder, p_buffer_iterator, sizeof(uint32_holder));
				p_buffer_iterator += sizeof(uint32_holder);
				indexed.m_NumberOfColors = uint32_holder;
				// Get number of subimages
				memcpy(&uint16_holder, p_buffer_iterator, sizeof(uint16_holder));
				p_buffer_iterator += sizeof(uint16_holder);
				indexed.m_NumberOfSubImages = uint16_holder;
				// Get red depth
				memcpy(&uint8_holder, p_buffer_iterator, sizeof(uint8_holder));
				p_buffer_iterator += sizeof(uint8_holder);
				indexed.m_RedDepth = uint8_holder;
				// Get green depth
				memcpy(&uint8_holder, p_buffer_iterator, sizeof(uint8_holder));
				p_buffer_iterator += sizeof(uint8_holder);
				indexed.m_GreenDepth = uint8_holder;
				// get blue depth
				memcpy(&uint8_holder, p_buffer_iterator, sizeof(uint8_holder));
				p_buffer_iterator += sizeof(uint8_holder);
				indexed.m_BlueDepth = uint8_holder;
				// Save to variant
				stci_header.m_Union = indexed;
				// Allocate for paletes
				size_t const file_section_size = indexed.m_NumberOfColors * PALETTE_ELEMENT_SIZE;
				assert(indexed.m_NumberOfColors == 256 && "Number of palletes mismatch");
				unsigned char *p_pallete = new unsigned char[file_section_size];
				p_buffer_iterator = reinterpret_cast<char*>(p_pallete);
				// Read pallete from file
				rFile.read(p_pallete, file_section_size);
				unsigned char *p_ETRLE_buffer = NULL;
				// SubImage structure
				struct SubImage
				{
					boost::uint32_t m_DataOffset,
						m_DataLength;
					boost::int16_t m_OffsetX,
						m_OffsetY;
					boost::uint16_t m_Height,
						m_Width;
				};
				// Load subimages
				static unsigned short const SUBIMAGE_SIZE = 16;
				size_t const sub_image_size = boost::get<STCIHeader::Indexed>(
					stci_header.m_Union).m_NumberOfSubImages * SUBIMAGE_SIZE;
				p_ETRLE_buffer = new unsigned char[sub_image_size];
				// Read sub image data
				rFile.read(p_ETRLE_buffer, sub_image_size);

				SubImage *p_etrle_object = reinterpret_cast<SubImage *>(p_ETRLE_buffer);
				//					assert(p_etrle_object->m_OffsetX == 0 && p_etrle_object->m_OffsetY == 0 && "Offset not implemented yet");
				// Read image data
				unsigned char *p_image_data = new unsigned char[stci_header.m_StoredSize];
				rFile.read(p_image_data, stci_header.m_StoredSize);
				// Load Application data
				if(stci_header.m_AppDataSize > 0)
				{
					assert(false && "Not implemented yet");
				}

				unsigned short number_of_subimages = boost::get<STCIHeader::Indexed>(stci_header.m_Union).m_NumberOfSubImages;
				// Create pixel buffer for each subimage and add it to sprite description
				for(unsigned short i = 0; i < number_of_subimages; i++)
				{
					unsigned char *p_image_data_iterator = p_image_data + p_etrle_object[i].m_DataOffset;
					unsigned short width = p_etrle_object[i].m_Width, 
						height = p_etrle_object[i].m_Height;
					// Buffer of new pixels
					unsigned char *p_new_px_buffer = new unsigned char[width * height * sizeof(unsigned int)];
					int pitch = width * sizeof(unsigned int);
					// Need to uncompress data
					if(stci_header.m_ETRLECompressed)
					{
						static unsigned short const STCI_TRANSPARENT = 0x80;
						static unsigned short const STCI_NON_TRANSPARENT = 0x00;
						static unsigned short const STCI_RUN_LIMIT = 0x7F;
						unsigned char* p_etrle_data_iterator = p_image_data + p_etrle_object[i].m_DataOffset;
						unsigned char* p_line_new_px_buffer = p_new_px_buffer;
						// Need to convert whole image
						bool was_new_line = true;
						for(size_t j = 0; j < p_etrle_object[i].m_DataLength;)
						{
							unsigned short no_pixels = 1;
							// Transparent pixels
							if(p_etrle_data_iterator[j] & STCI_TRANSPARENT)
							{
								was_new_line = false;
								// Get number of pixel
								no_pixels = p_etrle_data_iterator[j] & STCI_RUN_LIMIT;
								j++;
								// Set pixels and move forward
								memset(p_line_new_px_buffer, 0, sizeof(unsigned int) * no_pixels);
								p_line_new_px_buffer += no_pixels * sizeof(unsigned int);
								if(p_etrle_data_iterator[j] == 0)
									j++;
							}
							// Non-transparent pixels
							else
							{
								// Number of pixels to copy
								no_pixels = p_etrle_data_iterator[j++];
								// Set pixel data
								for(unsigned short k = 0; k < no_pixels; k++)
								{
									int palette_index = p_etrle_data_iterator[j++];
									unsigned char* p_pallete_entry = 
										p_pallete + palette_index * 3;
									// If we don't want to have shadow font
									if(Type == IT_FONT_WITHOUT_SHADOW && palette_index == 1)
									{
										// Set transparent color
										*p_line_new_px_buffer++ = 0;
										*p_line_new_px_buffer++ = 0;
										*p_line_new_px_buffer++ = 0;
										*p_line_new_px_buffer++ = 0;
									}
									// We want font with shadow or loading texture
									else
									{
										// Set color from pallete
										*p_line_new_px_buffer++ = p_pallete_entry[0];
										*p_line_new_px_buffer++ = p_pallete_entry[1];
										*p_line_new_px_buffer++ = p_pallete_entry[2];
										*p_line_new_px_buffer++ = 255;
									}

								}
							}
						}
					}
					CL_PixelBuffer px_buffer(width, height, pitch, 
						CL_PixelFormat::abgr8888, p_new_px_buffer, &detail::pixel_deleter);	
					sprite_desc.add_frame(px_buffer);
				}
				delete[] p_pallete;
				delete[] p_ETRLE_buffer;
				delete[] p_image_data;
			}
			break;
		}
		// Return sprite descriptor
		return sprite_desc;

	}
} /*detail*/ } /*sgp*/
namespace sgp
{
	STCIImageCodec::DecodeResult decode(Ogre::DataStreamPtr  &input) const
	{
		MemoryDataStream memStream(input, true);

		// decode image from PGF mem stream
		int w, h;
		UINT8 *data = decodePGF ((UINT8*)memStream.getPtr(), memStream.size(), w, h);
		ImageData* imgData = new ImageData();
		MemoryDataStreamPtr output(new MemoryDataStream(data, imgData->size, true));

		// set image properties
		imgData->depth = 1;
		imgData->width = w;
		imgData->height = h;
		imgData->num_mipmaps = 0;
		imgData->flags = 0;
		imgData->format = PF_R8G8B8;
		unsigned dstPitch = imgData->width * PixelUtil::getNumElemBytes(imgData->format);
		imgData->size = dstPitch * imgData->height;

		// return decoded image
		DecodeResult ret;
		ret.first = output;
		ret.second = CodecDataPtr(imgData);
		return ret;

	}

	Ogre::String STCIImageCodec::getType() const
	{
		return "sti";
	}
}
#endif

BOOLEAN STCILoadRGB( HIMAGE hImage, UINT16 fContents, HWFILE hFile, STCIHeader * pHeader );
BOOLEAN STCILoadIndexed( HIMAGE hImage, UINT16 fContents, HWFILE hFile, STCIHeader * pHeader );
BOOLEAN STCISetPalette( PTR pSTCIPalette, HIMAGE hImage );

BOOLEAN LoadSTCIFileToImage( HIMAGE hImage, UINT16 fContents )
{
	HWFILE			hFile;
	STCIHeader	Header;
	UINT32			uiBytesRead;
	image_type	TempImage;

	// Check that hImage is valid, and that the file in question exists
	Assert( hImage != NULL );

	TempImage = *hImage;

	CHECKF( FileExists( TempImage.ImageFile ) );

	// Open the file and read the header
	hFile = FileOpen( TempImage.ImageFile, FILE_ACCESS_READ, FALSE );
	CHECKF( hFile );

	if (!FileRead( hFile, &Header, STCI_HEADER_SIZE, &uiBytesRead ) || uiBytesRead != STCI_HEADER_SIZE || memcmp( Header.cID, STCI_ID_STRING, STCI_ID_LEN ) != 0 )
	{
		DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Problem reading STCI header." );
		FileClose( hFile );
		return( FALSE );
	}

	// Determine from the header the data stored in the file. and run the appropriate loader
	if (Header.fFlags & STCI_RGB)
	{
		if( !STCILoadRGB( &TempImage, fContents, hFile, &Header ) )
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Problem loading RGB image." );
			FileClose( hFile );
			return( FALSE );
		}
	}
	else if (Header.fFlags & STCI_INDEXED)
	{
		if( !STCILoadIndexed( &TempImage, fContents, hFile, &Header ) )
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Problem loading palettized image." );
			FileClose( hFile );
			return( FALSE );
		}
	}
	else
	{	// unsupported type of data, or the right flags weren't set!
		DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Unknown data organization in STCI file." );
		FileClose( hFile );
		return( FALSE );
	}

	// Requested data loaded successfully.
	FileClose( hFile );

	// Set some more flags in the temporary image structure, copy it so that hImage points
	// to it, and return.
	if (Header.fFlags & STCI_ZLIB_COMPRESSED)
	{
		TempImage.fFlags |= IMAGE_COMPRESSED;
	}
	TempImage.usWidth = Header.usWidth;
	TempImage.usHeight = Header.usHeight;
	TempImage.ubBitDepth = Header.ubDepth;
	*hImage = TempImage;

	return( TRUE );
}

BOOLEAN STCILoadRGB( HIMAGE hImage, UINT16 fContents, HWFILE hFile, STCIHeader * pHeader )
{
	UINT32			uiBytesRead;

	if (fContents & IMAGE_PALETTE && !(fContents & IMAGE_ALLIMAGEDATA))
	{ // RGB doesn't have a palette!
		return( FALSE );
	}

	if (fContents & IMAGE_BITMAPDATA)
	{
		// Allocate memory for the image data and read it in
		hImage->pImageData =	MemAlloc( pHeader->uiStoredSize );
		if (hImage->pImageData == NULL)
		{
			return( FALSE );
		}
		else if (!FileRead( hFile, hImage->pImageData, pHeader->uiStoredSize, &uiBytesRead ) || uiBytesRead != pHeader->uiStoredSize)
		{
			MemFree( hImage->pImageData );
			return( FALSE );
		}

		hImage->fFlags |= IMAGE_BITMAPDATA;

		if( pHeader->ubDepth == 16)
		{
			// ASSUMPTION: file data is 565 R,G,B

			if (gusRedMask != (UINT16) pHeader->RGB.uiRedMask || gusGreenMask != (UINT16) pHeader->RGB.uiGreenMask || gusBlueMask != (UINT16) pHeader->RGB.uiBlueMask )
			{
				// colour distribution of the file is different from hardware!	We have to change it!
				DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Converting to current RGB distribution!" );
				// Convert the image to the current hardware's specifications
				if (gusRedMask > gusGreenMask && gusGreenMask > gusBlueMask)
				{
					// hardware wants RGB!
					if (gusRedMask == 0x7C00 && gusGreenMask == 0x03E0 && gusBlueMask == 0x001F)
					{	// hardware is 555
						ConvertRGBDistribution565To555( hImage->p16BPPData, pHeader->usWidth * pHeader->usHeight );
						return( TRUE );
					}
					else if (gusRedMask == 0xFC00 && gusGreenMask == 0x03E0 && gusBlueMask == 0x001F)
					{
						ConvertRGBDistribution565To655( hImage->p16BPPData, pHeader->usWidth * pHeader->usHeight );
						return( TRUE );
					}
					else if (gusRedMask == 0xF800 && gusGreenMask == 0x07C0 && gusBlueMask == 0x003F)
					{
						ConvertRGBDistribution565To556( hImage->p16BPPData, pHeader->usWidth * pHeader->usHeight );
						return( TRUE );
					}
					else
					{
						// take the long route
						ConvertRGBDistribution565ToAny( hImage->p16BPPData, pHeader->usWidth * pHeader->usHeight );
						return( TRUE );
					}
				}
				else
				{
					// hardware distribution is not R-G-B so we have to take the long route!
					ConvertRGBDistribution565ToAny( hImage->p16BPPData, pHeader->usWidth * pHeader->usHeight );
					return( TRUE );
				}
			}
		}
	}
#ifdef JA2
	return( TRUE );
#else
// Anything else is an ERROR! --DB
	return(FALSE);
#endif
}


BOOLEAN STCILoadIndexed( HIMAGE hImage, UINT16 fContents, HWFILE hFile, STCIHeader * pHeader )
{
	UINT32			uiFileSectionSize;
	UINT32			uiBytesRead;
	PTR					pSTCIPalette;

	if (fContents & IMAGE_PALETTE)
	{ // Allocate memory for reading in the palette
		if (pHeader->Indexed.uiNumberOfColours != 256)
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Palettized image has bad palette size." );
			return( FALSE );
		}
		uiFileSectionSize = pHeader->Indexed.uiNumberOfColours * STCI_PALETTE_ELEMENT_SIZE;
		pSTCIPalette = MemAlloc( uiFileSectionSize );
		if (pSTCIPalette == NULL)
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Out of memory!" );
			FileClose( hFile );
			return( FALSE );
		}

		// ATE: Memset: Jan 16/99
		memset( pSTCIPalette, 0, uiFileSectionSize );

		// Read in the palette
		if (!FileRead( hFile, pSTCIPalette, uiFileSectionSize, &uiBytesRead ) || uiBytesRead != uiFileSectionSize)
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Problem loading palette!" );
			FileClose( hFile );
			MemFree( pSTCIPalette );
			return( FALSE );
		}
		else if (!STCISetPalette( pSTCIPalette, hImage ))
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Problem setting hImage-format palette!" );
			FileClose( hFile );
			MemFree( pSTCIPalette );
			return( FALSE );
		}
		hImage->fFlags |= IMAGE_PALETTE;
		// Free the temporary buffer
		MemFree( pSTCIPalette );
	}
	else if (fContents & (IMAGE_BITMAPDATA | IMAGE_APPDATA))
	{ // seek past the palette
		uiFileSectionSize = pHeader->Indexed.uiNumberOfColours * STCI_PALETTE_ELEMENT_SIZE;
		if (FileSeek( hFile, uiFileSectionSize, FILE_SEEK_FROM_CURRENT) == FALSE)
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Problem seeking past palette!" );
			FileClose( hFile );
			return( FALSE );
		}
	}
	if (fContents & IMAGE_BITMAPDATA)
	{
		if (pHeader->fFlags & STCI_ETRLE_COMPRESSED)
		{
			// load data for the subimage (object) structures
			Assert( sizeof( ETRLEObject ) == STCI_SUBIMAGE_SIZE );
			hImage->usNumberOfObjects = pHeader->Indexed.usNumberOfSubImages;
			uiFileSectionSize = hImage->usNumberOfObjects * STCI_SUBIMAGE_SIZE;
			hImage->pETRLEObject = (ETRLEObject *) MemAlloc( uiFileSectionSize );
			if (hImage->pETRLEObject == NULL)
			{
				DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Out of memory!" );
				FileClose( hFile );
				if (fContents & IMAGE_PALETTE)
				{
					MemFree( hImage->pPalette );
				}
				return( FALSE );
			}
			if (!FileRead( hFile, hImage->pETRLEObject, uiFileSectionSize, &uiBytesRead ) || uiBytesRead != uiFileSectionSize)
			{
				DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Error loading subimage structures!" );
				FileClose( hFile );
				if (fContents & IMAGE_PALETTE)
				{
					MemFree( hImage->pPalette );
				}
				MemFree( hImage->pETRLEObject );
				return( FALSE );
			}
			hImage->uiSizePixData = pHeader->uiStoredSize;
			hImage->fFlags |= IMAGE_TRLECOMPRESSED;
		}
		// allocate memory for and read in the image data
		hImage->pImageData = MemAlloc( pHeader->uiStoredSize );
		if (hImage->pImageData == NULL)
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Out of memory!" );
			FileClose( hFile );
			if (fContents & IMAGE_PALETTE)
			{
				MemFree( hImage->pPalette );
			}
			if (hImage->usNumberOfObjects > 0)
			{
				MemFree( hImage->pETRLEObject );
			}
			return( FALSE );
		}
		else if (!FileRead( hFile, hImage->pImageData, pHeader->uiStoredSize, &uiBytesRead ) || uiBytesRead != pHeader->uiStoredSize)
		{ // Problem reading in the image data!
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Error loading image data!" );
			FileClose( hFile );
			MemFree( hImage->pImageData );
			if (fContents & IMAGE_PALETTE)
			{
				MemFree( hImage->pPalette );
			}
			if (hImage->usNumberOfObjects > 0)
			{
				MemFree( hImage->pETRLEObject );
			}
			return( FALSE );
		}
		hImage->fFlags |= IMAGE_BITMAPDATA;
	}
	else if (fContents & IMAGE_APPDATA) // then there's a point in seeking ahead
	{
		if (FileSeek( hFile, pHeader->uiStoredSize, FILE_SEEK_FROM_CURRENT) == FALSE)
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Problem seeking past image data!" );
			FileClose( hFile );
			return( FALSE );
		}
	}

	if (fContents & IMAGE_APPDATA && pHeader->uiAppDataSize > 0)
	{
		// load application-specific data
		hImage->pAppData = (UINT8 *) MemAlloc( pHeader->uiAppDataSize );
		if (hImage->pAppData == NULL)
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Out of memory!" );
			FileClose( hFile );
			MemFree( hImage->pAppData );
			if (fContents & IMAGE_PALETTE)
			{
				MemFree( hImage->pPalette );
			}
			if (fContents & IMAGE_BITMAPDATA)
			{
				MemFree( hImage->pImageData );
			}
			if (hImage->usNumberOfObjects > 0)
			{
				MemFree( hImage->pETRLEObject );
			}
			return( FALSE );
		}
		if (!FileRead( hFile, hImage->pAppData, pHeader->uiAppDataSize, &uiBytesRead ) || uiBytesRead != pHeader->uiAppDataSize)
		{
			DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Error loading application-specific data!" );
			FileClose( hFile );
			MemFree( hImage->pAppData );
			if (fContents & IMAGE_PALETTE)
			{
				MemFree( hImage->pPalette );
			}
			if (fContents & IMAGE_BITMAPDATA)
			{
				MemFree( hImage->pImageData );
			}
			if (hImage->usNumberOfObjects > 0)
			{
				MemFree( hImage->pETRLEObject );
			}
			return( FALSE );
		}
		hImage->uiAppDataSize = pHeader->uiAppDataSize;;
		hImage->fFlags |= IMAGE_APPDATA;
	}
	else
	{
		hImage->pAppData = NULL;
		hImage->uiAppDataSize = 0;
	}
	return( TRUE );
}


BOOLEAN STCISetPalette( PTR pSTCIPalette, HIMAGE hImage )
{
	UINT16								usIndex;
	STCIPaletteElement *	pubPalette;

	pubPalette = (STCIPaletteElement *) pSTCIPalette;

	// Allocate memory for palette
	hImage->pPalette = (SGPPaletteEntry *) MemAlloc( sizeof( SGPPaletteEntry ) * 256 );
	memset( hImage->pPalette, 0, ( sizeof( SGPPaletteEntry ) * 256 ) );

	if ( hImage->pPalette == NULL )
	{
		return( FALSE );
	}

	// Initialize the proper palette entries
	for (usIndex = 0; usIndex < 256; usIndex++)
	{
		hImage->pPalette[ usIndex ].peRed	= pubPalette->ubRed;
		hImage->pPalette[ usIndex ].peGreen = pubPalette->ubGreen;
	hImage->pPalette[ usIndex ].peBlue	= pubPalette->ubBlue;
	hImage->pPalette[ usIndex ].peFlags = 0;
		pubPalette ++;
	}
	return TRUE;
}


BOOLEAN IsSTCIETRLEFile( CHAR8 * ImageFile )
{
	HWFILE		hFile;
	STCIHeader	Header;
	UINT32		uiBytesRead;

	CHECKF( FileExists( ImageFile ) );

	// Open the file and read the header
	hFile = FileOpen( ImageFile, FILE_ACCESS_READ, FALSE );
	CHECKF( hFile );

	if (!FileRead( hFile, &Header, STCI_HEADER_SIZE, &uiBytesRead ) || uiBytesRead != STCI_HEADER_SIZE || memcmp( Header.cID, STCI_ID_STRING, STCI_ID_LEN ) != 0 )
	{
		DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_3, "Problem reading STCI header." );
		FileClose( hFile );
		return( FALSE );
	}
	FileClose( hFile );
	if (Header.fFlags & STCI_ETRLE_COMPRESSED)
	{
	 return( TRUE );
	}
	else
	{
	 return( FALSE );
	}
}
